
#include "Shader.hpp"
#include "Core.hpp"
#include "Exception.hpp"
#include "Adapter.hpp"

namespace VoodooShader
{
	Shader::Shader(Core * parent, std::string filename, const char ** args)
		: mParent(parent)
	{
		this->mEffect = cgCreateEffectFromFile(parent->GetCGContext(), filename.c_str(), args);
		if ( !cgIsEffect(this->mEffect) )
		{
			Throw("Voodoo Core: Could not create shader.", this->mParent);
		}
	}
		
	Shader::Shader(Core * parent, CGeffect effect)
		: mParent(parent)
	{
		this->mEffect = effect;
	}

	Pass * Technique::GetPass(size_t index)
	{
		if ( index < this->mPasses.size() )
		{
			return this->mPasses[index];
		} else {
			//! @todo Fix NULL in Throw
			Throw("Voodoo Core: Invalid pass index (> pass count).", NULL);
		}
	}

	size_t Technique::NumPasses()
	{
		return this->mPasses.size();
	}

	Pass::Pass(Core * core, CGpass pass)
		: mPass(pass)
	{
		this->mName = cgGetPassName(pass);

		this->mVertexProgram = cgGetPassProgram(pass, GL_VERTEX_DOMAIN);
		this->mFragmentProgram = cgGetPassProgram(pass, GL_FRAGMENT_DOMAIN);
		this->mGeometryProgram = cgGetPassProgram(pass, GL_GEOMETRY_DOMAIN);

		this->mTarget = NULL;
		CGannotation targetAnnotation = cgGetNamedPassAnnotation(pass, "target");
		if ( cgIsAnnotation(targetAnnotation) )
		{
			if ( cgGetAnnotationType(targetAnnotation) == CG_STRING )
			{
				const char * targetName = cgGetStringAnnotationValue(targetAnnotation);
				this->mTarget = core->FindTexture(targetName);
			} else {
				//! @todo Fix this nested mess.
				core->GetLog()->Format("Voodoo Core: Effect %s, pass %s has annotation \"target\" of invalid type.")
					.With(cgGetEffectName(cgGetTechniqueEffect(cgGetPassTechnique(pass)))).With(this->mName).Done();
			}
		}
	}

	Texture * Pass::Target()
	{
		return this->mTarget;
	}

	const std::string & Pass::Name()
	{
		return this->mName;
	}

	CGprogram Pass::GeometryProgram()
	{
		return this->mGeometryProgram;
	}

	CGprogram Pass::FragmentProgram()
	{
		return this->mFragmentProgram;
	}

	CGprogram Pass::VertexProgram()
	{
		return this->mVertexProgram;
	}
}